<?php
/*
 * Copyright (c) 2008 Kilian Marjew <kilian@marjew.nl>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 *
 * @author Kilian Marjew (kilian@marjew.nl)
 * @url http://genusapis.marjew.nl/
 */

// All requires
require_once('lib/GenusApisUtil.php');
require_once('lib/GeneralException.php');
require_once('lib/HyvesApiException.php');
require_once('lib/OAuthBase.php');
require_once('lib/OAuthConsumer.php');
require_once('lib/OAuthRequestToken.php');
require_once('lib/OAuthAccessToken.php');
require_once('lib/OAuthUtil.php');
require_once('lib/GenusApisBatch.php');

class GenusApis {
    const DEFAULT_HA_FORMAT = 'xml';
    const DEFAULT_HA_FANCYLAYOUT = 'false';
    const DEFAULT_OAUTH_SIGNATURE_METHOD = "HMAC-SHA1";
    const HTTP_TYPE_GET = 'GET';
    const HTTP_TYPE_POST = 'POST';
    const API_URL = "http://data.hyves-api.nl/";
    const AUTHORIZE_URL = "http://www.hyves.nl/api/authorize/";

    public $oOAuthConsumer;
    public $timestampLastMethod;
    public $nonce;
    public $ha_version;

    public function __construct(OAuthConsumer $oOAuthConsumer, $ha_version) {
        $this->oOAuthConsumer = $oOAuthConsumer;
        $this->ha_version = $ha_version;
    }

    public function doMethod($ha_method, $sParams, OAuthBase $oOAuthToken = null, $httpType = self::HTTP_TYPE_POST) {
        $sDefaultParams = array(
                            "oauth_consumer_key" => $this->oOAuthConsumer->getKey(),
                            "oauth_timestamp" => $this->getOAuthTimestamp(),
                            "oauth_nonce" => $this->getOAuthNonce(),
                            "oauth_signature_method" => self::DEFAULT_OAUTH_SIGNATURE_METHOD,
                            "ha_method" => $ha_method,
                            "ha_version" => $this->ha_version,
                            "ha_format" => self::DEFAULT_HA_FORMAT,
                            "ha_fancylayout" => self::DEFAULT_HA_FANCYLAYOUT
                        );
        $oauth_consumer_secret = $this->oOAuthConsumer->getSecret();
        $oauth_token_secret = "";
        if ($oOAuthToken !== null)
        {
            $sDefaultParams["oauth_token"] = $oOAuthToken->getKey();
            $oauth_token_secret = $oOAuthToken->getSecret();
        }
        $sParams = $sParams + $sDefaultParams;
        $sParams["oauth_signature"] = GenusApisUtil::calculateOAuthSignature($httpType, self::API_URL, $sParams, $oauth_consumer_secret, $oauth_token_secret);

        $params = OAuthUtil::normalizeKeyValueParameters($sParams);
        $response = GenusApisUtil::doCurlHttpCall(self::API_URL, $params, ($httpType == self::HTTP_TYPE_POST));
        $oXml = simplexml_load_string($response);
        if ($oXml === false) {
            throw new GeneralException("Failed to parse response to XML. \nResponse:\n".$response);
        }
        $this->checkForErrors($oXml);
        return $oXml;
    }

    public function createBatch(OAuthBase $oOAuthToken = null, $sParams = null) {
        if ($sParams = null) {
            $sParams = array();
        }
        return new GenusApisBatch($oOAuthToken, $sParams, $this);
    }

    public function retrieveRequesttoken($aMethods, $expirationtype = 'default') {
        $oXml = $this->doMethod("auth.requesttoken", array("methods" => implode(',', $aMethods), "expirationtype" => $expirationtype));
        return new OAuthRequestToken((string)$oXml->oauth_token, (string)$oXml->oauth_token_secret);
    }

    public function getAuthorizeUrl(OAuthRequestToken $oOAuthRequestToken, $callback = null) {
        $url = self::AUTHORIZE_URL . "?oauth_token=" . $oOAuthRequestToken->getKey();
        if ($callback !== null) {
            $url .= "&oauth_callback=" . OAuthUtil::urlencodeRFC3986($callback);
        }
        return $url;
    }

    public function redirectToAuthorizeUrl(OAuthRequestToken $oOAuthRequestToken, $callback = null) {
        $url = $this->getAuthorizeUrl($oOAuthRequestToken, $callback);
        header("Location: " . $url);
    }

    public function retrieveAccesstoken(OAuthRequestToken $oOAuthRequestToken) {
        $oXml = $this->doMethod("auth.accesstoken", array(), $oOAuthRequestToken);
        return new OAuthAccessToken((string)$oXml->oauth_token, (string)$oXml->oauth_token_secret, (string)$oXml->userid, (string)$oXml->methods, (integer)$oXml->expiredate);
    }

    private function checkForErrors($oXml) {
        if (isset($oXml->error_code)) {
            throw new HyvesApiException($oXml->error_message, $oXml->error_code, $oXml);
        }
    }

    private function getOAuthTimestamp() {
        $timestamp = time();
        if ($this->timestampLastMethod == $timestamp) {
            $this->nonce++;
        } else {
            $this->timestampLastMethod = $timestamp;
            $this->nonce = 0;
        }
        return $this->timestampLastMethod;
    }

    private function getOAuthNonce() {
        $rand = rand(0, getrandmax());
        if (isset($_SERVER['REMOTE_ADDR'])) {
            $ipAddress = ip2long($_SERVER['REMOTE_ADDR']);
            return $this->nonce . "_" . $ipAddress . "_" . $rand;
        } else {
            return $this->nonce . "_" . $rand;
        }
    }

    public function getOAuthConsumer() {
        return $this->oOAuthConsumer;
    }


}
?>
